doubleMe x = x + x 

doubleUs x y = doubleMe x + doubleMe y

doubleSmallNumber x = if x < 100 then 
			doubleMe x 
			else x
doubleSmallNumber' x = if x < 100 then x else x + 1

bingBang xs = [if x < 100 then "BING"
			else "BANG"
		| x <- xs, x `mod` 3 == 0]
charAt i = [snd x | x <- zip [1..] [' '..'~'], fst x == i]
indexOf c = [ fst x | x <- zip [1..] [' '..'~'], snd x == c]

triangle x = [ (a, b, c) | 
			c <- [1..10], b <- [1..c], a <- [1..b],
			a^2 + b^2 == c^2, 
			sum [a, b, c] == x
     ]

euler1 x = sum [a| a <- [3,6..x-1], a `mod`5 /= 0] + sum [5, 10..x-1]

tail' :: [a] -> a
tail' [] = error "Bahhh"
tail' (x:[]) = x
tail' x = tail' (tail x)


test weight height
  | bmi <= first = "Small"
	| bmi <= second = "medium"
	| bmi <= third = "large"
	| otherwise = "Huge"
	where bmi =  weight / height ^ 2
	      (first, second, third) = (18.5, 25.0, 30.0)

initials :: String -> String -> String
initials firstname lastname = [x] ++ ". " ++ [y] ++ "."  
	where (x:_) = firstname
	      (y:_) = lastname

clacBmis xs = [bmi w h | (w, h) <- xs]
	where bmi weight height = weight / height ^ 2

calcBmis' xs = [bmi | (w, h) <-xs, let bmi = w / h ^2, bmi >= 25.5]

max' :: (Ord a) => [a] -> a
max' [] = error "no maximum"
max' [x] = x
max' (x:r) = max x (max' r)

replicate' :: (Num a, Ord a) => a -> a -> [a]
replicate' n x
 | n <= 0 = []
 | otherwise = x : replicate' (n-1) x


elem' :: (Eq a) => a -> [a] -> Bool
elem' _ [] = False
elem' a (x:xs) 
 | a == x = True
 | otherwise = elem' a xs

fibonacci :: (Num a) => a -> a
fibonacci 1 = 1
fibonacci 2 = 2
fibonacci x = fibonacci (x-2) + fibonacci (x-1)

euler2 = sum [y| y <- (takeWhile (<4000000) [fibonacci x | x <- [1..]]), even y]

fib [] = 1
fib [x] = x + 1
fib (x1:x2:_) = x1 + x2

fiba xs 
 | nextFib > 4000000 = xs
 | otherwise = fiba (fib xs : xs)
 where nextFib = fib xs 

euler2' = sum [y | y <- fiba [] , even y]

applyTwice :: (a -> a) -> a -> a
applyTwice f x = f (f x)

zipWith' :: (a -> b -> c) -> [a] -> [b] -> [c]
zipWith' f [] _ = []
zipWith' f _ [] = []
zipWith' f (a:as) (b:bs) = (f a b) : zipWith' f  as bs

prime :: (Integral a) => a -> Bool
prime a = null [x | x <- [2.. round (sqrt (fromIntegral a))], a `mod` x == 0]

euler3 :: (Integral a) => a ->  a
euler3 x = head [y | y <- [root, root - 1..2], x `mod` y == 0, prime y]
	where root = round (sqrt (fromIntegral x))


sieve (x:xs) = x : sieve (filter (\y -> y `mod` x /= 0) xs)
primes = sieve (2:[3,5..])

primeFactors 1 (x:xs) = x
primeFactors n all@(x:xs) 
 | n `mod` x == 0 = primeFactors (n `div` x) all
 | otherwise = primeFactors n xs

euler3' n = primeFactors n primes

products = [product| x <- [999, 998..100], y <- [999, 998..100], let product = x * y, show product == reverse (show product)]
